﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

namespace Neto.Files;

/// <summary>
///     ** 描述：文件公共类
///     ** 创始时间：2010-2-28
///     ** 修改时间：-
///     ** 修改人：sunkaixuan
///     ** 使用说明：
/// </summary>
public class FileHelper
{
    #region 字段定义

    /// <summary>
    ///     同步标识
    /// </summary>
    private static readonly object sync = new();

    #endregion 字段定义

    #region 检测指定目录是否存在

    /// <summary>
    ///     检测指定目录是否存在
    /// </summary>
    /// <param name="directoryPath">目录的绝对路径</param>
    public static bool IsExistDirectory(string directoryPath)
    {
        return Directory.Exists(directoryPath);
    }

    #endregion 检测指定目录是否存在

    #region 检测指定文件是否存在

    /// <summary>
    ///     检测指定文件是否存在,如果存在则返回true。
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static bool IsExistFile(string filePath)
    {
        return File.Exists(filePath);
    }

    #endregion 检测指定文件是否存在

    #region 检测指定目录是否为空

    /// <summary>
    ///     检测指定目录是否为空
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    public static bool IsEmptyDirectory(string directoryPath)
    {
        try
        {
            //判断是否存在文件
            var fileNames = GetFileNames(directoryPath);
            if (fileNames.Length > 0) return false;
            //判断是否存在文件夹
            var directoryNames = GetDirectories(directoryPath);
            if (directoryNames.Length > 0) return false;
            return true;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    #endregion 检测指定目录是否为空

    #region 创建文 件

    /// <summary>
    ///     创建一个文件
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static void CreateFile(string filePath)
    {
        try
        {
            //如果文件不存在则创建该文件
            if (!IsExistFile(filePath))
            {
                //获取文件目录路径
                var directoryPath = GetDirectoryFromFilePath(filePath);
                //如果文件的目录不存在，则创建目录
                CreateDirectory(directoryPath);
                lock (sync)
                    //创建文件
                    using (var fs = new FileStream(filePath, FileMode.OpenOrCreate))
                    {
                    }
            }
        }
        catch
        {
        }
    }

    #endregion 创建文 件

    #region 创建一个文件,并将字节流写入文件

    /// <summary>
    ///     创建一个文件,并将字节流写入文件。
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <param name="buffer">二进制流数据</param>
    public static void CreateFile(string filePath, byte[] buffer)
    {
        try
        {
            //如果文件不存在则创建该文件
            if (!IsExistFile(filePath))
            {
                //获取文件目录路径
                var directoryPath = GetDirectoryFromFilePath(filePath);
                //如果文件的目录不存在，则创建目录
                CreateDirectory(directoryPath);
                //创建一个FileInfo对象
                var file = new FileInfo(filePath);
                //创建文件
                using (var fs = file.Create())
                    //写入二进制流
                    fs.Write(buffer, 0, buffer.Length);
            }
        }
        catch
        {
        }
    }

    #endregion 创建一个文件,并将字节流写入文件

    #region 从文件绝对路径中获取目录路径

    /// <summary>
    ///     从文件绝对路径中获取目录路径
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static string GetDirectoryFromFilePath(string filePath)
    {
        //实例化文件
        var file = new FileInfo(filePath);
        //获取目录信息
        var directory = file.Directory;
        //返回目录路径
        return directory.FullName;
    }

    #endregion 从文件绝对路径中获取目录路径

    #region 获取文本文件的行数

    /// <summary>
    ///     获取文本文件的行数
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static int GetLineCount(string filePath)
    {
        //创建流读取器
        using (var reader = new StreamReader(filePath))
        {
            //行数
            var i = 0;
            while (true)
                //如果读取到内容就把行数加1
                if (reader.ReadLine() != null)
                    i++;
                else
                    break;
            //返回行数
            return i;
        }
    }

    #endregion 获取文本文件的行数

    #region 向文本文件的尾部追加内容

    /// <summary>
    ///     向文本文件的尾部追加内容
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <param name="text">写入的内容</param>
    public static void AppendText(string filePath, string text)
    {
        //======= 追加内容 =======
        try
        {
            lock (sync)
                //创建流写入器
                using (var writer = new StreamWriter(filePath, true))
                    writer.WriteLine(text);
        }
        catch
        {
        }
    }

    #endregion 向文本文件的尾部追加内容

    #region 将现有文件的内容复制到新文件中

    /// <summary>
    ///     将源文件的内容复制到目标文件中
    /// </summary>
    /// <param name="sourceFilePath">源文件的绝对路径</param>
    /// <param name="destFilePath">目标文件的绝对路径</param>
    public static void CopyTo(string sourceFilePath, string destFilePath)
    {
        //有效性检测
        if (!IsExistFile(sourceFilePath)) return;
        try
        {
            //检测目标文件的目录是否存在，不存在则创建
            var destDirectoryPath = GetDirectoryFromFilePath(destFilePath);
            CreateDirectory(destDirectoryPath);
            //复制文件
            var file = new FileInfo(sourceFilePath);
            file.CopyTo(destFilePath, true);
        }
        catch
        {
        }
    }

    #endregion 将现有文件的内容复制到新文件中

    #region 将文件移动到指定目录( 剪切 )

    /// <summary>
    ///     将文件移动到指定目录( 剪切 )
    /// </summary>
    /// <param name="sourceFilePath">需要移动的源文件的绝对路径</param>
    /// <param name="descDirectoryPath">移动到的目录的绝对路径</param>
    public static void MoveToDirectory(string sourceFilePath, string descDirectoryPath)
    {
        //有效性检测
        if (!IsExistFile(sourceFilePath)) return;
        try
        {
            //获取源文件的名称
            var sourceFileName = GetFileName(sourceFilePath);
            //如果目标目录不存在则创建
            CreateDirectory(descDirectoryPath);
            //如果目标中存在同名文件,则删除
            if (IsExistFile(descDirectoryPath + "\\" + sourceFileName))
                DeleteFile(descDirectoryPath + "\\" + sourceFileName);
            //目标文件路径
            string descFilePath;
            if (!descDirectoryPath.EndsWith(@"\"))
                descFilePath = descDirectoryPath + "\\" + sourceFileName;
            else
                descFilePath = descDirectoryPath + sourceFileName;
            //将文件移动到指定目录
            File.Move(sourceFilePath, descFilePath);
        }
        catch
        {
        }
    }

    #endregion 将文件移动到指定目录( 剪切 )

    #region 将文件移动到指定目录，并指定新的文件名( 剪切并改名 )

    /// <summary>
    ///     将文件移动到指定目录，并指定新的文件名( 剪切并改名 )
    /// </summary>
    /// <param name="sourceFilePath">需要移动的源文件的绝对路径</param>
    /// <param name="descFilePath">目标文件的绝对路径</param>
    public static void Move(string sourceFilePath, string descFilePath)
    {
        //有效性检测
        if (!IsExistFile(sourceFilePath)) return;
        try
        {
            //获取目标文件目录
            var descDirectoryPath = GetDirectoryFromFilePath(descFilePath);
            //创建目标目录
            CreateDirectory(descDirectoryPath);
            //将文件移动到指定目录
            File.Move(sourceFilePath, descFilePath);
        }
        catch
        {
        }
    }

    #endregion 将文件移动到指定目录，并指定新的文件名( 剪切并改名 )

    #region 将流读取到缓冲区中

    /// <summary>
    ///     将流读取到缓冲区中
    /// </summary>
    /// <param name="stream">原始流</param>
    public static byte[] StreamToBytes(Stream stream)
    {
        try
        {
            //创建缓冲区
            var buffer = new byte[stream.Length];
            //读取流
            stream.Read(buffer, 0, Convert.ToInt32(stream.Length));
            //返回流
            return buffer;
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            //关闭流
            stream.Close();
        }
    }

    #endregion 将流读取到缓冲区中

    #region 将文件读取到缓冲区中

    /// <summary>
    ///     将文件读取到缓冲区中
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static byte[] FileToBytes(string filePath)
    {
        //获取文件的大小
        var fileSize = GetFileSize(filePath);
        //创建一个临时缓冲区
        var buffer = new byte[fileSize];
        //创建一个文件
        var file = new FileInfo(filePath);
        //创建一个文件流
        using (var fs = file.Open(FileMode.Open))
        {
            //将文件流读入缓冲区
            fs.Read(buffer, 0, fileSize);
            return buffer;
        }
    }

    #endregion 将文件读取到缓冲区中

    #region 从文件的绝对路径中获取文件名( 包含扩展名 )

    /// <summary>
    ///     从文件的绝对路径中获取文件名( 包含扩展名 )
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static string GetFileName(string filePath)
    {
        //获取文件的名称
        var fi = new FileInfo(filePath);
        return fi.Name;
    }

    #endregion 从文件的绝对路径中获取文件名( 包含扩展名 )

    #region 从文件的绝对路径中获取文件名( 不包含扩展名 )

    /// <summary>
    ///     从文件的绝对路径中获取文件名( 不包含扩展名 )
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static string GetFileNameNoExtension(string filePath)
    {
        //获取文件的名称
        var fi = new FileInfo(filePath);
        return fi.Name.Split('.')[0];
    }

    #endregion 从文件的绝对路径中获取文件名( 不包含扩展名 )

    #region 从文件的绝对路径中获取扩展名

    /// <summary>
    ///     从文件的绝对路径中获取扩展名
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static string GetExtension(string filePath)
    {
        //获取文件的名称
        var fi = new FileInfo(filePath);
        return fi.Extension;
    }

    #endregion 从文件的绝对路径中获取扩展名

    #region 清空指定目录

    /// <summary>
    ///     清空指定目录下所有文件及子目录,但该目录依然保存.
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    public static void ClearDirectory(string directoryPath)
    {
        if (IsExistDirectory(directoryPath))
        {
            //删除目录中所有的文件
            var fileNames = GetFileNames(directoryPath);
            for (var i = 0; i < fileNames.Length; i++) DeleteFile(fileNames[i]);
            //删除目录中所有的子目录
            var directoryNames = GetDirectories(directoryPath);
            for (var i = 0; i < directoryNames.Length; i++) DeleteDirectory(directoryNames[i]);
        }
    }

    #endregion 清空指定目录

    #region 清空文件内容

    /// <summary>
    ///     清空文件内容
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static void ClearFile(string filePath)
    {
        //删除文件
        File.Delete(filePath);
        //重新创建该文件
        CreateFile(filePath);
    }

    #endregion 清空文件内容

    #region 根据路径得到文件流

    /// <summary>
    ///     根据指定的文件路径获取文件的字节流。
    /// </summary>
    /// <param name="Path">文件的路径。</param>
    /// <returns>文件的字节流。</returns>
    public static byte[] GetFileSream(string Path)
    {
        // 初始化字节缓冲区
        byte[] buffer = null;
        // 使用FileInfo打开文件并以只读方式读取文件内容
        using (var stream = new FileInfo(Path).OpenRead())
        {
            // 根据文件长度创建缓冲区，并读取文件内容到缓冲区
            buffer = new byte[stream.Length];
            stream.Read(buffer, 0, Convert.ToInt32(stream.Length));
        }

        // 返回读取的文件字节流
        return buffer;
    }

    #endregion 根据路径得到文件流

    #region 合并路径

    /// <summary>
    ///     按照数字顺序合并URL。
    /// </summary>
    /// <param name="urls">一个包含多个URL字符串的参数数组。</param>
    /// <returns>合并后的URL字符串。如果输入为空或仅包含一个URL，则直接返回该URL。如果输入有效但不含任何URL，则返回null。</returns>
    public static string MergeUrl(params string[] urls)
    {
        // 检查输入URL数组是否为空或零长度，如果是，则直接返回null
        if (urls == null || urls.Length == 0)
            return null;
        // 如果输入只包含一个URL，进行预处理后直接返回
        if (urls.Length == 1)
        {
            urls = urls.Where(it => it != null).ToArray();
            return urls[0];
        }

        // 过滤掉null元素，准备进行合并
        urls = urls.Where(it => it != null).ToArray();

        // 使用StringBuilder来构建最终的URL
        var reval = new StringBuilder();
        var i = 0;
        var slash = '\\'; // 默认路径分隔符为反斜杠
        // 检查是否有URL包含斜杠，若有，则使用斜杠作为路径分隔符
        if (!urls.Any(it => it.Contains(slash.ToString()))) slash = '/';
        foreach (var url in urls)
        {
            var itUrl = url;
            var isFirst = i == 0; // 判断当前URL是否为第一个
            var isLast = i == urls.Length - 1; // 判断当前URL是否为最后一个
            // 移除第一个URL的前导斜杠，添加最后一个URL的后导斜杠（如果不存在的话）
            if (!isFirst) itUrl = itUrl.TrimStart(slash);
            if (!isLast) itUrl = url.TrimEnd(slash) + slash;
            ++i;
            reval.Append(itUrl); // 将处理后的URL片段添加到最终URL中
            itUrl = null; // 清理局部变量
        }

        // 调用GetRuntimeDirectory处理最终URL并返回
        return GetRuntimeDirectory(reval.ToString());
    }

    #endregion 合并路径

    /// <summary>
    ///     获取指定文件的完整路径所对应的文件夹路径。
    /// </summary>
    /// <param name="filePath">要获取其所在文件夹路径的文件的完整路径。</param>
    /// <returns>指定文件所在的文件夹路径。</returns>
    /// <exception cref="ArgumentNullException">
    ///     当<paramref name="filePath" />为null或空字符串时抛出此异常。
    /// </exception>
    public static string GetDirectoryPathFromFilePath(string filePath)
    {
        // 检查输入参数是否为空
        if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException(nameof(filePath), "文件路径不能为空");

        // 使用Path类的GetDirectoryName方法获取文件所在的目录路径
        var directoryPath = Path.GetDirectoryName(filePath);

        // 返回获取到的文件夹路径
        return directoryPath;
    }

    /// <summary>
    ///     通过指定的文件路径，读取并返回该文件的相关信息。
    /// </summary>
    /// <param name="filePath">要读取其信息的文件的完整路径。</param>
    /// <returns><see cref="FileInfo" />对象，包含了指定文件的详细信息。</returns>
    /// <exception cref="ArgumentNullException">
    ///     当<paramref name="filePath" />为null或空字符串时抛出此异常。
    /// </exception>
    /// <exception cref="FileNotFoundException">
    ///     当指定路径的文件不存在时抛出此异常。
    /// </exception>
    public static FileInfo ReadFileInfo(string filePath)
    {
        // 检查输入参数是否为空
        if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException(nameof(filePath), "文件路径不能为空");

        // 创建并返回一个FileInfo对象，用于获取文件详细信息
        return new FileInfo(filePath);
    }

    #region 压缩文件验证，支持的格式包括：ZIP、RAR、7Z、TAR、GZ、TAR.GZ、BZ、BZ2、TAR.BZ2。

    /// <summary>
    ///     检查指定文件是否为压缩文件，支持的格式包括：ZIP、RAR、7Z、TAR、GZ、TAR.GZ、BZ、BZ2、TAR.BZ2。
    /// </summary>
    /// <param name="filePath">待检查文件的完整路径。</param>
    /// <returns>如果文件是支持的压缩文件格式之一，则返回true；否则返回false。</returns>
    public static bool IsCompressedFile(string filePath)
    {
        if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
            throw new ArgumentException($"The specified file '{filePath}' does not exist.");

        using (var stream = File.OpenRead(filePath))
        {
            var headerBytes = new byte[10]; // 常见压缩文件头长度一般在前几字节内，这里取一个足够容纳大部分格式头标识的长度

            // 读取文件头
            var bytesRead = stream.Read(headerBytes, 0, headerBytes.Length);

            if (bytesRead < headerBytes.Length)
                // 无法读取到足够的头信息，可能是文件太小或读取异常，视为非压缩文件
                return false;

            // 根据不同压缩格式的文件头标识进行判断
            var headerHex = BitConverter.ToString(headerBytes).Replace("-", "");

            // 获取文件路径的扩展名，并转换为小写格式
            var extension = Path.GetExtension(filePath).ToLowerInvariant();

            switch (headerHex)
            {
                case "50-4B-03-04": // ZIP
                case "50-4B-05-06": // ZIP64
                case "50-4B-07-08": // ZIP64
                    return true;

                case "52-61-72-21": // RAR
                    return true;

                case "37-7A-BC-AF-27-1C": // 7Z
                    return true;

                case "1F-9D": // TAR（旧UStar格式）
                case "1F-8B": // GZ
                case "75-73-74-61-72": // TAR（新UStar格式）
                    // 对于TAR和GZ单独出现，或以.tar或.gz结尾的情况，已经可以确定文件类型

                    return extension == ".tar" || extension == ".gz";

                default:
                    // 处理复合压缩格式，如tar.gz、tar.bz2等
                    if (extension.EndsWith(".tar.gz", StringComparison.OrdinalIgnoreCase))
                    {
                        // 检查是否为GZ格式，同时文件名以.tar.gz结尾
                        if (headerHex.StartsWith("1F-8B")) return true;
                    }
                    else if (extension.EndsWith(".tar.bz2", StringComparison.OrdinalIgnoreCase))
                        // 检查是否为BZ2格式，同时文件名以.tar.bz2结尾
                        if (headerHex.StartsWith("42-5A-68"))
                            return true;

                    return false;
            }
        }
    }

    #endregion

    #region 创建一个目录

    /// <summary>
    ///     创建一个目录
    /// </summary>
    /// <param name="directoryPath">目录的绝对路径</param>
    public static void CreateDirectory(string directoryPath)
    {
        //如果目录不存在则创建该目录
        if (!IsExistDirectory(directoryPath)) Directory.CreateDirectory(directoryPath);
    }

    /// <summary>
    ///     创建一个目录
    /// </summary>
    /// <param name="filePath">文件绝对路径</param>
    public static void CreateDirectoryByFilePath(string filePath)
    {
        var fileDirPath = GetDirectoryFromFilePath(filePath);
        //如果目录不存在则创建该目录
        if (!IsExistDirectory(fileDirPath)) Directory.CreateDirectory(fileDirPath);
    }

    #endregion 创建一个目录

    #region 获取文件路并自动创建目录

    /// <summary>
    ///     根据指定的文件目录、编号、文件名生成文件完整路径，并确保目录存在
    /// </summary>
    /// <typeparam name="T">编号的类型，可以是任意类型</typeparam>
    /// <param name="directory">文件所在目录</param>
    /// <param name="code">文件的编号</param>
    /// <param name="fileName">文件名</param>
    /// <returns>生成的文件完整路径</returns>
    public string GetFiePathAndCreateDirectoryByCode<T>(string directory, T code, string fileName)
    {
        // 检查目录参数是否为null
        if (directory == null) throw new ArgumentNullException("FileSugar.GetCreatePath.directory");
        // 移除目录路径末尾的'/'
        directory = directory.TrimEnd('/');
        // 构建文件路径
        var path = new StringBuilder("{0}//{1}//{2}").AppendFormat(directory, code, fileName).ToString();
        // 从文件路径中提取目录部分
        directory = Path.GetDirectoryName(path);
        // 检查目录是否存在，不存在则创建
        if (!IsExistDirectory(directory)) CreateDirectory(directory);
        return path;
    }

    /// <summary>
    ///     根据指定的文件目录、当前日期、文件名生成文件完整路径，并确保目录存在
    /// </summary>
    /// <typeparam name="T">无意义，仅为匹配泛型约束</typeparam>
    /// <param name="directory">文件所在目录</param>
    /// <param name="fileName">文件名</param>
    /// <returns>生成的包含当前日期的文件完整路径</returns>
    public string GetFiePathAndCreateDirectoryByDate<T>(string directory, string fileName)
    {
        // 检查目录参数是否为null
        if (directory == null) throw new ArgumentNullException("FileSugar.GetCreatePath.directory");
        // 移除目录路径末尾的'/'
        directory = directory.TrimEnd('/');
        // 构建包含当前年月日的文件路径
        var path = new StringBuilder("{0}//{1}//{2}//{3}//{4}")
            .AppendFormat(directory, DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, fileName).ToString();
        // 从文件路径中提取目录部分
        directory = Path.GetDirectoryName(path);
        // 检查目录是否存在，不存在则创建
        if (!IsExistDirectory(directory)) CreateDirectory(directory);
        return path;
    }

    #endregion 获取文件路并自动创建目录

    #region 获取缩略图名称

    /// <summary>
    ///     根据提供的文件名和索引获取最小图片的文件名
    /// </summary>
    /// <param name="filename">原始文件名</param>
    /// <param name="index">图片索引，用于生成新的文件名</param>
    /// <returns>如果成功则返回新的文件名，否则返回空字符串</returns>
    public static string GetMinPic(string filename, int index)
    {
        var str = "";
        // 检查文件名是否为空
        if (string.IsNullOrEmpty(filename))
            return str;
        // 查找文件名中最后一个"."的位置，用于分割文件名和扩展名
        var nLastDot = filename.LastIndexOf(".");
        if (nLastDot == -1)
            return str;
        // 生成新的文件名
        str = filename.Substring(0, nLastDot) + "_" + index + filename.Substring(nLastDot, filename.Length - nLastDot);
        // 如果索引为-1，则不添加索引编号
        if (index == -1)
            str = filename.Substring(0, nLastDot) + filename.Substring(nLastDot, filename.Length - nLastDot);
        return str;
    }

    /// <summary>
    ///     获取指定目录中的缩略图片路径
    /// </summary>
    /// <param name="dir">图片所在的目录</param>
    /// <param name="filename">原始文件名</param>
    /// <param name="index">图片索引，用于生成新的文件名</param>
    /// <returns>如果成功则返回缩略图片的完整路径，否则返回空字符串</returns>
    public static string GetMinPic(string dir, string filename, int index)
    {
        if (string.IsNullOrEmpty(filename))
            return "";
        // 当索引小于0时，将其设置为0
        if (index < 0)
            index = 0;
        var minPic = string.Empty;
        // 生成新的文件名
        minPic = string.Format("{0}_{1}{2}", Path.GetFileNameWithoutExtension(filename), index,
            Path.GetExtension(filename));
        // 如果提供了目录，则将文件名和目录结合生成完整路径
        if (!string.IsNullOrEmpty(dir))
            minPic = Path.Combine(dir, minPic);
        return minPic;
    }

    #endregion 获取缩略图名称

    #region 检测指定目录中是否存在指定的文件

    /// <summary>
    ///     检测指定目录中是否存在指定的文件,若要搜索子目录请使用重载方法.
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    /// <param name="searchPattern">
    ///     模式字符串，"*"代表0或N个字符，"?"代表1个字符。
    ///     范例："Log*.xml"表示搜索所有以Log开头的Xml文件。
    /// </param>
    /// <returns>如果指定文件存在则返回true，否则返回false。</returns>
    public static bool Contains(string directoryPath, string searchPattern)
    {
        try
        {
            // 尝试获取指定目录中匹配搜索模式的文件列表
            var fileNames = GetFileNames(directoryPath, searchPattern, false);
            // 判断是否找到了指定的文件
            if (fileNames.Length == 0)
                return false;
            return true;
        }
        catch (Exception ex)
        {
            // 如果发生异常，则将异常抛出
            throw ex;
        }
    }


    /// <summary>
    ///     检测指定目录中是否存在指定的文件
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    /// <param name="searchPattern">
    ///     模式字符串，"*"代表0或N个字符，"?"代表1个字符。
    ///     范例："Log*.xml"表示搜索所有以Log开头的Xml文件。
    /// </param>
    /// <param name="isSearchChild">是否搜索子目录</param>
    public static bool Contains(string directoryPath, string searchPattern, bool isSearchChild)
    {
        try
        {
            //获取指定的文件列表
            var fileNames = GetFileNames(directoryPath, searchPattern, true);
            //判断指定文件是否存在
            if (fileNames.Length == 0)
                return false;
            return true;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    #endregion 检测指定目录中是否存在指定的文件

    #region 创建一个文件,并将字符串写入文件

    #region 重载1

    /// <summary>
    ///     创建一个文件,并将字符串写入文件。
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <param name="text">字符串数据</param>
    public static void CreateFile(string filePath, string text)
    {
        CreateFile(filePath, text, Encoding.UTF8);
    }

    #endregion 重载1

    #region 重载2

    /// <summary>
    ///     创建一个文件,并将字符串写入文件。
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <param name="text">要写入文件的字符串数据</param>
    /// <param name="encoding">写入文件时使用的字符编码</param>
    public static void CreateFile(string filePath, string text, Encoding encoding)
    {
        try
        {
            // 检查文件是否存在，如果不存在则进行创建
            if (!IsExistFile(filePath))
            {
                // 获取文件所在目录路径，并创建该目录
                var directoryPath = GetDirectoryFromFilePath(filePath);
                CreateDirectory(directoryPath);

                // 创建文件并写入字符串数据
                var file = new FileInfo(filePath);
                using (var stream = file.Create()) // 创建文件流
                using (var writer = new StreamWriter(stream, encoding)) // 创建StreamWriter用于写入文本
                {
                    // 写入字符串数据到文件
                    writer.Write(text);
                    // 确保数据被写入到物理文件中
                    writer.Flush();
                }
            }
        }
        catch (Exception ex)
        {
            // 捕获并忽略所有可能发生的异常
            throw;
        }
    }


    /// <summary>
    ///     创建一个文件,并将字符串写入文件。
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <param name="text">字符串数据</param>
    /// <param name="encoding">字符编码</param>
    public static void CreateFileReplace(string filePath, string text, Encoding encoding)
    {
        try
        {
            //如果文件不存在则创建该文件
            //获取文件目录路径
            var directoryPath = GetDirectoryFromFilePath(filePath);
            //如果文件的目录不存在，则创建目录
            CreateDirectory(directoryPath);
            //创建文件
            var file = new FileInfo(filePath);
            using (var stream = file.Create())
            using (var writer = new StreamWriter(stream, encoding))
            {
                //写入字符串
                writer.Write(text);
                //输出
                writer.Flush();
            }
        }
        catch
        {
        }
    }

    #endregion 重载2

    #endregion 创建一个文件,并将字符串写入文件

    #region 获取一个文件的长度

    /// <summary>
    ///     获取一个文件的长度,单位为Byte
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static int GetFileSize(string filePath)
    {
        //创建一个文件对象
        var fi = new FileInfo(filePath);
        //获取文件的大小
        return (int)fi.Length;
    }

    /// <summary>
    ///     获取一个文件的长度,单位为KB
    /// </summary>
    /// <param name="filePath">文件的路径</param>
    public static double GetFileSizeByKB(string filePath)
    {
        //创建一个文件对象
        var fi = new FileInfo(filePath);
        //获取文件的大小
        return Convert.ToDouble(Convert.ToDouble(fi.Length) / 1024);
    }

    /// <summary>
    ///     获取一个文件的长度,单位为MB
    /// </summary>
    /// <param name="filePath">文件的路径</param>
    public static double GetFileSizeByMB(string filePath)
    {
        //创建一个文件对象
        var fi = new FileInfo(filePath);
        //获取文件的大小
        return Convert.ToDouble(Convert.ToDouble(fi.Length) / 1024 / 1024);
    }

    #endregion 获取一个文件的长度

    #region 获取指定目录中的文件列表

    /// <summary>
    ///     获取指定目录中所有文件列表
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    public static string[] GetFileNames(string directoryPath)
    {
        //如果目录不存在，则抛出异常
        if (!IsExistDirectory(directoryPath)) throw new FileNotFoundException();
        //获取文件列表
        return Directory.GetFiles(directoryPath);
    }

    /// <summary>
    ///     获取指定目录及子目录中所有文件列表
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    /// <param name="searchPattern">
    ///     模式字符串，"*"代表0或N个字符，"?"代表1个字符。
    ///     范例："Log*.xml"表示搜索所有以Log开头的Xml文件。
    /// </param>
    /// <param name="isSearchChild">是否搜索子目录</param>
    public static string[] GetFileNames(string directoryPath, string searchPattern, bool isSearchChild)
    {
        //如果目录不存在，则抛出异常
        if (!IsExistDirectory(directoryPath)) throw new FileNotFoundException();
        try
        {
            if (isSearchChild)
                return Directory.GetFiles(directoryPath, searchPattern, SearchOption.AllDirectories);
            return Directory.GetFiles(directoryPath, searchPattern, SearchOption.TopDirectoryOnly);
        }
        catch (IOException ex)
        {
            throw ex;
        }
    }

    #endregion 获取指定目录中的文件列表

    #region 获取指定目录中的子目录列表

    /// <summary>
    ///     获取指定目录中所有子目录列表,若要搜索嵌套的子目录列表,请使用重载方法.
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    public static string[] GetDirectories(string directoryPath)
    {
        try
        {
            return Directory.GetDirectories(directoryPath);
        }
        catch (IOException ex)
        {
            throw ex;
        }
    }

    /// <summary>
    ///     获取指定目录及子目录中所有子目录列表
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    /// <param name="searchPattern">
    ///     模式字符串，"*"代表0或N个字符，"?"代表1个字符。
    ///     范例："Log*.xml"表示搜索所有以Log开头的Xml文件。
    /// </param>
    /// <param name="isSearchChild">是否搜索子目录</param>
    public static string[] GetDirectories(string directoryPath, string searchPattern, bool isSearchChild)
    {
        try
        {
            if (isSearchChild)
                return Directory.GetDirectories(directoryPath, searchPattern, SearchOption.AllDirectories);
            return Directory.GetDirectories(directoryPath, searchPattern, SearchOption.TopDirectoryOnly);
        }
        catch (IOException ex)
        {
            throw ex;
        }
    }

    #endregion 获取指定目录中的子目录列表

    #region 向文本文件写入内容

    /// <summary>
    ///     向文本文件中写入内容
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <param name="text">写入的内容</param>
    public static void WriteText(string filePath, string text)
    {
        WriteText(filePath, text, Encoding.UTF8);
    }

    /// <summary>
    ///     向文本文件中写入内容
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <param name="text">写入的内容</param>
    /// <param name="encoding">编码</param>
    public static void WriteText(string filePath, string text, Encoding encoding)
    {
        //向文件写入内容
        File.WriteAllText(filePath, text, encoding);
    }

    #endregion 向文本文件写入内容

    #region 将文件读取到字符串中

    /// <summary>
    ///     将文件读取到字符串中
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static string FileToString(string filePath)
    {
        return FileToString(filePath, Encoding.UTF8);
    }

    /// <summary>
    ///     将文件读取到字符串中
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <param name="encoding">字符编码</param>
    public static string FileToString(string filePath, Encoding encoding)
    {
        //创建流读取器
        var reader = new StreamReader(filePath, encoding);
        try
        {
            //读取流
            return reader.ReadToEnd();
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            //关闭流读取器
            reader.Close();
        }
    }

    #endregion 将文件读取到字符串中

    #region 删除指定文件

    /// <summary>
    ///     删除指定文件
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    public static void DeleteFile(string filePath)
    {
        // 检查文件是否存在，如果存在则删除
        if (IsExistFile(filePath)) File.Delete(filePath);
    }

    /// <summary>
    ///     尝试删除指定文件
    /// </summary>
    /// <param name="filePath">文件的绝对路径</param>
    /// <returns>如果删除成功返回true，否则返回false</returns>
    public static bool TryDeleteFile(string filePath)
    {
        try
        {
            DeleteFile(filePath); // 尝试删除文件
            return true;
        }
        catch (Exception ex)
        {
            // 删除文件时发生异常，返回false
            return false;
        }
    }

    #endregion 删除指定文件

    #region 删除指定目录

    /// <summary>
    ///     删除指定目录及其所有子目录
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    public static void DeleteDirectory(string directoryPath)
    {
        // 检查目录是否存在，若存在则递归删除该目录及其所有子目录
        if (IsExistDirectory(directoryPath)) Directory.Delete(directoryPath, true);
    }

    /// <summary>
    ///     尝试删除指定目录及其所有子目录
    /// </summary>
    /// <param name="directoryPath">指定目录的绝对路径</param>
    /// <returns>如果删除成功则返回true，否则返回false</returns>
    public static bool TryDeleteDirectory(string directoryPath)
    {
        try
        {
            // 尝试删除目录，若删除成功则返回true
            DeleteDirectory(directoryPath);
            return true;
        }
        catch (Exception ex)
        {
            // 若删除过程中发生异常，则捕获异常并返回false
            return false;
        }
    }

    #endregion 删除指定目录

    #region 写文件

    /// <summary>
    ///     写文件
    /// </summary>
    /// <param name="strFilePath">文件路径</param>
    /// <param name="strValue">要写入文件的内容</param>
    public static void WriteFile(string strFilePath, string strValue)
    {
        // 创建FileInfo对象以获取文件信息
        var oFile = new FileInfo(strFilePath);
        // 如果文件所在的目录不存在，则创建该目录
        if (!oFile.Directory.Exists)
            oFile.Directory.Create();
        // 如果文件不存在，则创建新文件
        if (!oFile.Exists)
            oFile.Create().Close();
        // 使用UTF-8编码打开文件以写入内容，如果文件存在则追加，否则创建新文件
        var oWrite = new StreamWriter(strFilePath, false, Encoding.UTF8);
        oWrite.Write(strValue);
        // 确保所有写入操作都完成并关闭流
        oWrite.Flush();
        oWrite.Close();
    }

    /// <summary>
    ///     写文件
    /// </summary>
    /// <param name="strFilePath">文件路径</param>
    /// <param name="strValue">要写入文件的内容</param>
    /// <param name="charset">写入文件时使用的字符编码</param>
    public static void WriteFile(string strFilePath, string strValue, string charset)
    {
        // 创建FileInfo对象以获取文件信息
        var oFile = new FileInfo(strFilePath);
        // 如果文件所在的目录不存在，则创建该目录
        if (!oFile.Directory.Exists)
            oFile.Directory.Create();
        // 如果文件不存在，则创建新文件
        if (!oFile.Exists)
            oFile.Create().Close();
        // 根据指定的字符编码打开文件以写入内容，如果文件存在则追加，否则创建新文件
        var oWrite = new StreamWriter(strFilePath, false, Encoding.GetEncoding(charset));
        oWrite.Write(strValue);
        // 确保所有写入操作都完成并关闭流
        oWrite.Flush();
        oWrite.Close();
    }

    #endregion 写文件

    #region 路径处理

    /// <summary>
    ///     获取运行时目录。
    ///     根据执行环境（Linux 或 Windows），此函数将返回相应系统的目录路径。
    ///     如果无法确定运行环境，则返回输入的路径。
    /// </summary>
    /// <param name="path">输入的路径。</param>
    /// <returns>根据运行环境返回的相应系统的目录路径，或输入的路径。</returns>
    public static string GetRuntimeDirectory(string path)
    {
        // 判断是否为Linux运行环境
        if (IsLinuxRunTime())
            return GetLinuxDirectory(path); // 返回Linux环境下的目录
        // 判断是否为Windows运行环境
        if (IsWindowRunTime())
            return GetWindowDirectory(path); // 返回Windows环境下的目录
        return path; // 如果既不是Linux也不是Windows环境，返回输入的路径
    }


    /// <summary>
    ///     OSPlatform.Windows监测运行环境
    /// </summary>
    /// <returns></returns>
    public static bool IsWindowRunTime()
    {
        return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
    }

    /// <summary>
    ///     OSPlatform.Linux运行环境
    /// </summary>
    /// <returns></returns>
    public static bool IsLinuxRunTime()
    {
        return RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
    }

    /// <summary>
    ///     获取linux路径
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string GetLinuxDirectory(string path)
    {
        var pathTemp = Path.Combine(path);
        return pathTemp.Replace("\\", "/");
    }

    /// <summary>
    ///     获取windows路径
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string GetWindowDirectory(string path)
    {
        var pathTemp = Path.Combine(path);
        return pathTemp.Replace("/", "\\");
    }

    #endregion 路径处理


    #region 判断是否为图片(JPEG、PNG、GIF、BMP、TIFF、WebP)、word、excel、ppt、pdf、zip、rar、7z

    /// <summary>
    ///     判断指定路径的文件是否为图片，通过检查文件头（魔数）实现。
    /// </summary>
    /// <param name="filePath">要判断的文件的完整路径。</param>
    /// <returns>如果文件是图片类型则返回true，否则返回false。</returns>
    /// <exception cref="ArgumentNullException">
    ///     当<paramref name="filePath" />为null或空字符串时抛出此异常。
    /// </exception>
    /// <exception cref="FileNotFoundException">
    ///     当指定路径的文件不存在时抛出此异常。
    /// </exception>
    /// <exception cref="IOException">
    ///     在读取文件头过程中发生I/O错误时抛出此异常。
    /// </exception>
    private static byte[] GetFileByHeader(string filePath)
    {
        // 检查输入参数是否为空
        if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException(nameof(filePath), "文件路径不能为空");

        // 读取文件头前几个字节（通常足够判断图片类型）
        const int HeaderSize = 8;
        byte[] headerBytes;

        using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        headerBytes = new byte[HeaderSize];
        var read = fileStream.Read(headerBytes, 0, HeaderSize);

        return headerBytes;
    }


    /// <summary>
    ///     判断指定路径的文件是否为图片，通过检查文件头（魔数）实现。
    ///     文件格式有：JPEG、PNG、GIF、BMP、TIFF、WebP
    /// </summary>
    /// <param name="filePath">要判断的文件的完整路径。</param>
    /// <returns>如果文件是图片类型则返回true，否则返回false。</returns>
    public static bool IsImageFileByHeader(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath);
        // 检查文件头是否符合已知图片类型的特征
        return IsJpeg(headerBytes) || IsPng(headerBytes) || IsGif(headerBytes) || IsBmp(headerBytes) ||
               IsTiff(headerBytes) ||
               IsWebP(headerBytes);
    }

    /// <summary>
    ///     判断给定的字节流是否为JPEG格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合JPEG格式，则返回true；否则返回false。</returns>
    public static bool IsJpeg(byte[] headerBytes)
    {
        // 检查字节流是否至少包含4个字节，并且这4个字节是否对应JPEG文件头的标识
        return headerBytes.Length >= 4 &&
               headerBytes[0] == 0xFF && headerBytes[1] == 0xD8 &&
               headerBytes[2] == 0xFF && (headerBytes[3] == 0xE0 || headerBytes[3] == 0xE1);
    }

    /// <summary>
    ///     判断给定的字节流是否为PNG格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合PNG格式，则返回true；否则返回false。</returns>
    private static bool IsPng(byte[] headerBytes)
    {
        // 检查字节流是否至少包含8个字节，并且这8个字节是否对应PNG文件头的标识
        return headerBytes.Length >= 8 &&
               headerBytes[0] == 0x89 && headerBytes[1] == 0x50 && headerBytes[2] == 0x4E && headerBytes[3] == 0x47 &&
               headerBytes[4] == 0x0D && headerBytes[5] == 0x0A && headerBytes[6] == 0x1A && headerBytes[7] == 0x0A;
    }

    /// <summary>
    ///     判断给定的字节流是否为GIF格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合GIF格式，则返回true；否则返回false。</returns>
    private static bool IsGif(byte[] headerBytes)
    {
        // 检查字节流是否至少包含6个字节，并且这6个字节是否对应GIF文件头的标识
        return headerBytes.Length >= 6 &&
               headerBytes[0] == 0x47 && headerBytes[1] == 0x49 && headerBytes[2] == 0x46 &&
               headerBytes[3] == 0x38 && (headerBytes[4] == 0x37 || headerBytes[4] == 0x39) && headerBytes[5] == 0x61;
    }

    /// <summary>
    ///     判断给定的字节流是否为BMP格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合BMP格式，则返回true；否则返回false。</returns>
    private static bool IsBmp(byte[] headerBytes)
    {
        // 检查字节流是否至少包含2个字节，并且这2个字节是否对应BMP文件头的标识
        return headerBytes.Length >= 2 &&
               headerBytes[0] == 0x42 && headerBytes[1] == 0x4D;
    }

    /// <summary>
    ///     判断给定的字节流是否为TIFF格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合TIFF格式，则返回true；否则返回false。</returns>
    private static bool IsTiff(byte[] headerBytes)
    {
        // 检查字节流是否至少包含4个字节，并且这4个字节是否对应TIFF文件头的标识
        return headerBytes.Length >= 4 &&
               ((headerBytes[0] == 0x49 && headerBytes[1] == 0x49 && headerBytes[2] == 0x2A &&
                 headerBytes[3] == 0x00) ||
                (headerBytes[0] == 0x4D && headerBytes[1] == 0x4D && headerBytes[2] == 0x00 && headerBytes[3] == 0x2A));
    }

    /// <summary>
    ///     判断给定的字节流是否为WebP格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合WebP格式，则返回true；否则返回false。</returns>
    private static bool IsWebP(byte[] headerBytes)
    {
        // 检查字节流是否至少包含12个字节，并且这12个字节是否对应WebP文件头的标识
        return headerBytes.Length >= 12 &&
               headerBytes[0] == 0x52 && headerBytes[1] == 0x49 && headerBytes[2] == 0x46 && headerBytes[3] == 0x46 &&
               headerBytes[8] == 0x57 && headerBytes[9] == 0x45 && headerBytes[10] == 0x42 && headerBytes[11] == 0x50;
    }

    /// <summary>
    ///     检查文件是否为JPEG格式。
    /// </summary>
    /// <param name="filePath">要检查的文件路径。</param>
    /// <returns>如果文件是JPEG格式，则返回true；否则返回false。</returns>
    public static bool IsJpeg(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath);
        // 检查文件头是否符合已知图片类型的特征
        return IsJpeg(headerBytes);
    }

    /// <summary>
    ///     检查文件是否为PNG格式。
    /// </summary>
    /// <param name="filePath">要检查的文件路径。</param>
    /// <returns>如果文件是PNG格式，则返回true；否则返回false。</returns>
    public static bool IsPng(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath);
        return IsPng(headerBytes);
    }

    /// <summary>
    ///     检查文件是否为GIF格式。
    /// </summary>
    /// <param name="filePath">要检查的文件路径。</param>
    /// <returns>如果文件是GIF格式，则返回true；否则返回false。</returns>
    public static bool IsGif(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath);
        return IsGif(headerBytes);
    }

    /// <summary>
    ///     检查文件是否为BMP格式。
    /// </summary>
    /// <param name="filePath">要检查的文件路径。</param>
    /// <returns>如果文件是BMP格式，则返回true；否则返回false。</returns>
    public static bool IsBmp(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath);
        return IsBmp(headerBytes);
    }

    /// <summary>
    ///     检查文件是否为TIFF格式。
    /// </summary>
    /// <param name="filePath">要检查的文件路径。</param>
    /// <returns>如果文件是TIFF格式，则返回true；否则返回false。</returns>
    public static bool IsTiff(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath);
        return IsTiff(headerBytes);
    }

    /// <summary>
    ///     检查文件是否为WEBP格式。
    /// </summary>
    /// <param name="filePath">要检查的文件路径。</param>
    /// <returns>如果文件是WEBP格式，则返回true；否则返回false。</returns>
    public static bool IsWebP(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath);
        return IsWebP(headerBytes);
    }

    #endregion

    #region 验证是否是PDF、word、excel、ppt等文件格式

    /// <summary>
    ///     检查文件是否为PDF格式。
    /// </summary>
    /// <param name="filePath">文件的路径。</param>
    /// <returns>如果文件是PDF格式，则返回true；否则返回false。</returns>
    public static bool IsPdf(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath); // 通过文件头获取文件的二进制数据
        return IsPdf(headerBytes); // 检查二进制数据是否属于PDF文件
    }

    /// <summary>
    ///     检查文件是否为Word格式。
    /// </summary>
    /// <param name="filePath">文件的路径。</param>
    /// <returns>如果文件是Word格式，则返回true；否则返回false。</returns>
    public static bool IsWord(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath); // 通过文件头获取文件的二进制数据
        return IsWord(headerBytes); // 检查二进制数据是否属于Word文件
    }

    /// <summary>
    ///     检查文件是否为Excel格式。
    /// </summary>
    /// <param name="filePath">文件的路径。</param>
    /// <returns>如果文件是Excel格式，则返回true；否则返回false。</returns>
    public static bool IsExcel(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath); // 通过文件头获取文件的二进制数据
        return IsExcel(headerBytes); // 检查二进制数据是否属于Excel文件
    }

    /// <summary>
    ///     检查文件是否为PPT格式。
    /// </summary>
    /// <param name="filePath">文件的路径。</param>
    /// <returns>如果文件是PPT格式，则返回true；否则返回false。</returns>
    public static bool IsPpt(string filePath)
    {
        var headerBytes = GetFileByHeader(filePath); // 通过文件头获取文件的二进制数据
        return IsPpt(headerBytes); // 检查二进制数据是否属于PPT文件
    }

    /// <summary>
    ///     判断给定的字节流是否为PDF格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合PDF格式，则返回true；否则返回false。</returns>
    private static bool IsPdf(byte[] headerBytes)
    {
        // PDF 文件头通常以"%PDF"字符串开头，紧跟一个版本号（如"%PDF-1.7")，且版本号后通常有一个回车符（0x0D）和换行符（0x0A）。
        // 由于版本号可能变化，此处仅检查前缀及第一个回车换行对来确认基本的PDF文件头结构。

        // 检查字节流是否至少包含足够的字节来容纳最小的PDF文件头标识（即"%PDF" + 版本号 + 回车换行）
        const int MinPdfHeaderLength = 5; // "%PDF" + 1个字节版本号 + 回车换行
        if (headerBytes.Length < MinPdfHeaderLength) return false;

        // 验证前缀
        if (headerBytes[0] != '%' || headerBytes[1] != 'P' || headerBytes[2] != 'D' || headerBytes[3] != 'F')
            return false;

        // 验证第一个回车换行对
        if (headerBytes[MinPdfHeaderLength - 2] != 0x0D || headerBytes[MinPdfHeaderLength - 1] != 0x0A) return false;

        // 至此，已经确认了最小的PDF文件头结构，可以初步判断为PDF文件
        return true;
    }

    /// <summary>
    ///     判断给定的字节流是否为Microsoft Word (.doc/.docx)格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合Word格式，则返回true；否则返回false。</returns>
    private static bool IsWord(byte[] headerBytes)
    {
        // DOCX 文件头为 PK 打包标记，后跟特定目录结构（.docx为Office Open XML格式）
        // DOC 文件头通常为 "D0 CF 11 E0 A1 B1 1A E1"，但可能有其他变体

        // DOCX 格式检查
        if (headerBytes.Length >= 2 &&
            headerBytes[0] == 0x50 && headerBytes[1] == 0x4B) // PK打包标记
            // 进一步检查可能的子文件名或目录结构以提高准确性（例如 "_rels/.rels" 或 "[Content_Types].xml")
            // 此处省略具体实现，仅示例基本DOCX格式检查
            return true;

        // DOC 格式检查
        if (headerBytes.Length >= 8 &&
            headerBytes[0] == 0xD0 && headerBytes[1] == 0xCF &&
            headerBytes[2] == 0x11 && headerBytes[3] == 0xE0 &&
            headerBytes[4] == 0xA1 && headerBytes[5] == 0xB1 &&
            headerBytes[6] == 0x1A && headerBytes[7] == 0xE1)
            return true;

        return false;
    }

    /// <summary>
    ///     判断给定的字节流是否为Microsoft Excel (.xls/.xlsx)格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合Excel格式，则返回true；否则返回false。</returns>
    private static bool IsExcel(byte[] headerBytes)
    {
        // XLSX 文件头同样为 PK 打包标记，后跟特定目录结构（.xlsx为Office Open XML格式）
        // XLS 文件头通常为 "D0 CF 11 E0 A1 B1 1A E1"，但可能有其他变体

        // XLSX 格式检查
        if (headerBytes.Length >= 2 &&
            headerBytes[0] == 0x50 && headerBytes[1] == 0x4B) // PK打包标记
            // 进一步检查可能的子文件名或目录结构以提高准确性（例如 "_rels/.rels" 或 "[Content_Types].xml")
            // 此处省略具体实现，仅示例基本XLSX格式检查
            return true;

        // XLS 格式检查
        if (headerBytes.Length >= 8 &&
            headerBytes[0] == 0xD0 && headerBytes[1] == 0xCF &&
            headerBytes[2] == 0x11 && headerBytes[3] == 0xE0 &&
            headerBytes[4] == 0xA1 && headerBytes[5] == 0xB1 &&
            headerBytes[6] == 0x1A && headerBytes[7] == 0xE1)
            // 后续可能需要检查复合文档内的特定子对象标识以确认为Excel文件，此处简化处理
            return true;

        return false;
    }

    /// <summary>
    ///     判断给定的字节流是否为Microsoft PowerPoint (.ppt/.pptx)格式。
    /// </summary>
    /// <param name="headerBytes">文件头的字节流。</param>
    /// <returns>如果文件头符合PowerPoint格式，则返回true；否则返回false。</returns>
    private static bool IsPpt(byte[] headerBytes)
    {
        // PPTX 文件头同样为 PK 打包标记，后跟特定目录结构（.pptx为Office Open XML格式）
        // PPT 文件头通常为 "D0 CF 11 E0 A1 B1 1A E1"，但可能有其他变体

        // PPTX 格式检查
        if (headerBytes.Length >= 2 &&
            headerBytes[0] == 0x50 && headerBytes[1] == 0x4B) // PK打包标记
            // 进一步检查可能的子文件名或目录结构以提高准确性（例如 "_rels/.rels" 或 "[Content_Types].xml")
            // 此处省略具体实现，仅示例基本PPTX格式检查
            return true;

        // PPT 格式检查
        if (headerBytes.Length >= 8 &&
            headerBytes[0] == 0xD0 && headerBytes[1] == 0xCF &&
            headerBytes[2] == 0x11 && headerBytes[3] == 0xE0 &&
            headerBytes[4] == 0xA1 && headerBytes[5] == 0xB1 &&
            headerBytes[6] == 0x1A && headerBytes[7] == 0xE1)
            // 后续可能需要检查复合文档内的特定子对象标识以确认为PowerPoint文件，此处简化处理
            return true;

        return false;
    }

    #endregion
}